home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 2: CDPD 1
/
Almathera Ten on Ten - Disc 2: CDPD 1.iso
/
pd
/
276-300
/
299
/
rxil
/
src
/
check_port.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-14
|
9KB
|
426 lines
/* check_port.c */
/* Copyright © 1989 by Donald T. Meyer, Stormgate Software
* All Rights Reserved
*/
#include "rxil.h"
#include <string.h>
static void handle_message( struct RexxMsg *rexxmsg );
static void handle_rexx_message( struct RexxMsg *rexxmsg );
static void handle_return( struct RxilInvocation *rxi );
static int parse_inplace( char *p, char **argptr, int maxargs );
/*------------------------------------------------------------------*/
/* Functions */
/*------------------------------------------------------------------*/
/* NAME
* RxilCheckPort
*
* SYNOPSIS
* RxilCheckPort();
*
* FUNCTION
* Called by the client program's eventloop upon recieving a message
* at one of the ports.
* This handles the dispatching ( via RxilDispatch() ) of ARexx
* commands, the launching of "looped back" macros, and receiving
* the replys to macro invocation messages which we have sent to
* Rexxmaster.
*
* This is a "safe" call in that if the ARexx library was unopened
* or the port opening failed, nothing will go boom!
*
* INPUTS
* None
*
* RESULT
* None
*
* SIDES
*
* HISTORY
* 01-Aug-89 Creation.
* 18-Nov-89 Changed an (incorrect) error return code in line 212.
*
* BUGS
*
* SEE ALSO
* RxilInit(), RxilDispatch()
*/
void RxilCheckPort( void )
{
struct RexxMsg *rexxmsg;
/* Make call "safe" even if RxilInit() failed */
if( global_rdef == NULL )
{
return;
}
if( RxilCheckCancel() == TRUE )
{
/* It would appear that a cancel requester was posted, and
* the user clicked it!
*/
RxilCancel();
}
if( global_rdef->SecretPort )
{
while( rexxmsg = (struct RexxMsg *)
GetMsg( global_rdef->SecretPort ) )
{
global_rdef->FromRexx = RXIL_SECRET;
handle_message( rexxmsg );
global_rdef->FromRexx = 0;
}
}
if( global_rdef->PublicPort )
{
while( rexxmsg = (struct RexxMsg *)
GetMsg( global_rdef->PublicPort ) )
{
global_rdef->FromRexx = RXIL_PUBLIC;
handle_message( rexxmsg );
global_rdef->FromRexx = 0;
}
}
/* Do we want to clear the Abort flag? */
if( RxilPending() == FALSE )
{
if( global_rdef->CReq != NULL )
{
RxilEndCancel();
}
if( FlagIsClear( global_rdef->Flags, RXIL_NO_CLEARABORT ) )
{
global_rdef->Abort = FALSE;
}
}
}
/* This routine is called with the message received at any rexx port.
* These messages will be of two broad classes.
* The first is a reply from a command or function which we invoked
* by sending a packet to RexxMaster.
*
* The second is a command sent to our application by an ARexx
* program. This could potentialy be from the public port or from
* the uniquely-named private port.
*/
static void handle_message( struct RexxMsg *rexxmsg )
{
struct RxilInvocation *rxi;
/* Decide if it is a reply */
for( rxi=global_rdef->Invocations; rxi; rxi=rxi->Next )
{
/* Is this an invocation reply? */
if( rexxmsg == rxi->RexxMsg )
{
/* Yes */
handle_return( rxi );
return;
}
}
/* Apparently not a completion message. Should be a command
* from a Rexx program.
*/
if( IsRexxMsg(rexxmsg) == FALSE )
{
/* This message is not from ARexx. Don't touch it,
* just Reply() it and return.
*/
ReplyMsg( (struct Message *)rexxmsg );
return;
}
/* The message is from an ARexx program */
handle_rexx_message( rexxmsg );
}
/* This will take a command message received from an ARexx program
* and handle the dispatching and replying.
* This message MUST be from an ARexx program!
*/
static void handle_rexx_message( struct RexxMsg *rexxmsg )
{
char *cmdbuf;
struct RxilInvocation *child_rxi;
/* Default to okay code. */
rexxmsg->rm_Result1 = RC_OK;
rexxmsg->rm_Result2 = 0;
/* Are we still open for business? */
if( global_rdef->Abort == TRUE )
{
/* Nope! */
rexxmsg->rm_Result1 = RXERR_ABORTED;
ReplyMsg( (struct Message *)rexxmsg );
return;
}
/* Handle the message contents */
/* Just to be squeaky clean, since Bill says to affect only the
* result fields, copy this into a buffer before parsing.
*
* NOTE: Even though an Argstring can by definition contain
* embedded null's, the command line is treated as though it
* were null terminated.
*/
cmdbuf = AllocMem( strlen( ARG0(rexxmsg) )+1, 0 );
if( cmdbuf == NULL )
{
rexxmsg->rm_Result1 = RXERR_NO_MEMORY;
return;
}
strcpy( cmdbuf, ARG0(rexxmsg) );
/* Parse the command string */
global_rdef->ArgCount =
parse_inplace( cmdbuf, &(global_rdef->Arg[0]), RXIL_MAX_ARGS );
if( global_rdef->ArgCount == 0 )
{
rexxmsg->rm_Result1 = RXERR_UNKNOWN_CMD;
FreeMem( cmdbuf, strlen( ARG0(rexxmsg) ) );
return;
}
RxilDispatch( rexxmsg, global_rdef->Arg[0] );
FreeMem( cmdbuf, strlen( ARG0(rexxmsg)+1 ) );
/* Look at macro loopback */
if( ( rexxmsg->rm_Result1 == RXERR_UNKNOWN_CMD ) &&
FlagIsClear( global_rdef->Flags, RXIL_NOLAUNCH ) )
{
/* Unknown command. Try to launch it as an ARexx macro. */
child_rxi = RxilCreateRxi( ARG0(rexxmsg), RXCOMM );
if( child_rxi != NULL )
{
if( FlagIsSet( rexxmsg->rm_Action, RXFF_RESULT ) )
{
SetFlag( child_rxi->ActionFlags, RXFF_RESULT );
}
child_rxi->Parent = rexxmsg;
if( RxilLaunch( child_rxi ) == 0 )
{
/* Launched successfully */
return; /* Return without replying */
}
else
{
/* Launch failure */
RxilDeleteRxi( child_rxi );
rexxmsg->rm_Result1 = RXERR_FAILED;
}
}
else
{
/* Unable to create RxilInvocation structure */
rexxmsg->rm_Result1 = RXERR_NO_MEMORY;
}
}
RxilCheckResult( rexxmsg );
ReplyMsg( (struct Message *)rexxmsg );
}
static void handle_return( struct RxilInvocation *rxi )
{
rxi->State = RXIL_STATE_RETURNED;
if( rxi->CommAddr == global_rdef->SecretPortName )
{
/* This implies that the locked flag was set while
* this ran. Decrement the lock count.
*/
--(global_rdef->LockCount);
}
if( rxi->Parent == NULL )
{
/* This was originated by the client. Let the client
* worry about handling the return and doing the cleanup.
*/
return;
}
/* This is the return for a program which was "looped" back out
* to ARexx.
*/
/* Pass thru?? the result */
rxi->Parent->rm_Result1 = rxi->RexxMsg->rm_Result1;
rxi->Parent->rm_Result2 = rxi->RexxMsg->rm_Result2;
RxilCheckResult( rxi->Parent );
/* Reply to the parent */
ReplyMsg( (struct Message *)(rxi->Parent) );
/* Cleanup the invocation RexxMsg */
/* Zero these to prevent the cleanup routine from freeing
* the return Argstring.
*/
rxi->RexxMsg->rm_Result1 = 0;
rxi->RexxMsg->rm_Result2 = 0;
/* Clear these to prevent the cleanup routine from closing
* streams which were inherited from the parent.
*/
rxi->RexxMsg->rm_Stdin = NULL;
rxi->RexxMsg->rm_Stdout = NULL;
RxilCleanupReturn( rxi );
/* And free the RxilInvocation structure */
RxilDeleteRxi( rxi );
}
/* This is intended to be a very memory efficient parsing procedure.
* The length of the options is limited only by the length of the
* input line buffer (owned by the caller). The number of arguments which
* can be parsed out of an input string is limited by the size of the
* pointer array, which is also owned by the caller.
* Note that this WILL MODIFY the contents of the line passed in the
* buffer. If this is un-desirable, copy the string to a scratch buffer
* and pass that.
*
* The calling should look something like:
* char *myargpointers[10];
* int myargcount;
* char buf[100];
*
* gets( buf );
* myargcount = inplace_parse( buf, myargpointers, 10 );
*/
static int parse_inplace( char *p, char **argptr, int maxargs )
{
BOOL inparen = FALSE, inarg = FALSE;
char *argstart = 0; /* Does not really need to be initialized */
int argcount = 0;
while( (*p != '\0') && (argcount < maxargs) )
{
switch( *p )
{
case ' ':
case '\t':
/* Whitespace */
if( (inarg == TRUE) && (inparen == FALSE) )
{
/* We got one! */
*p = '\0'; /* place a delimiting null */
argptr[argcount++] = argstart;
inarg = FALSE;
inparen = FALSE;
}
break;
case '"':
if( inparen == TRUE )
{
/* This is closing paren */
/* We got one! */
*p = '\0'; /* place a delimiting null */
argptr[argcount++] = argstart;
inarg = FALSE;
inparen = FALSE;
}
else
{
/* Opening paren */
if( inarg == TRUE )
{
/* Deal with the previous arg first */
*p = '\0'; /* place a delimiting null */
argptr[argcount++] = argstart;
}
inparen = TRUE;
inarg = TRUE;
argstart = p+1;
}
break;
default:
/* A character we want in an argument string */
if( inarg == FALSE )
{
inarg = TRUE;
argstart = p;
}
break;
}
p++;
}
if( (inarg == TRUE) && (argcount < maxargs) )
argptr[argcount++] = argstart;
return( argcount );
}